﻿using System;
using System.Windows.Forms;
using System.Drawing;
using Qurihara;
using System.Collections;
using System.Xml;
using Qurihara.Anm;
using System.Threading;
using System.Net;
using Qurihara.QBasic;
using System.Text;
using System.Collections.Generic;

namespace Qurihara.OSCCom
{
    public class TCPComCore : IComCore
    {
        private TcpComServer server = null;

        //protected System.Windows.Forms.Timer timer;
        //private static Mutex mutInvalidated = new Mutex();

        private static bool received = false;
        private static string _adr, _data;

        protected string name = "default_name";
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        protected string ip = "localhost";
        public string Ip
        {
            get { return ip; }
        }
        protected int mPort = 5501;
        public int MPort
        {
            get { return mPort; }
        }
        private static int mPortMax = 5700;

        public event MessageEventHandler MessageReceived;

        private bool connected = false;
        public bool IsConnected
        {
            get { return connected; }
        }

        private string serverIP;
        private int serverPort;
        private static ArrayList usedPortList;
        static TCPComCore()
        {
            usedPortList = new ArrayList();
            usedPortList = ArrayList.Synchronized(usedPortList);
        }

        public TCPComCore()
        {
            server = new TcpComServer();
        }

        #region Configuration

        public virtual void Initialize()
        {
            //timer = new System.Windows.Forms.Timer();
            //timer.Interval = 200;
            //timer.Tick += new EventHandler(timer_Tick);
            //timer.Enabled = true;
            //timer.Start();
            InitOSC();
        }
        public virtual void Dispose()
        {
            Disconnect();
            //timer.Stop();
            //timer.Enabled = false;
            //timer.Dispose();
        }

        private void InitOSC()
        {
            string p = "";
            //if (Util.GetStringProperty("OscQRViewClientPlugin.MyPort", ref p))
            if (Util.GetStringProperty("OSCCom.MyPort", ref p))
            {
                mPort = int.Parse(p);
            }

            // mPortはどんどんインクリメントしてチェックしましょう。
            connected = false;
            while (!connected)
            {
                try
                {
                    connected = Connect(mPort);
                    if (!connected)
                    {
                        if (mPort < mPortMax)
                        {
                            //MessageBox.Show(mPort.ToString()+"番ポートが開けませんでした。続行します。");
                        }
                        else
                        {
                            MessageBox.Show(mPort.ToString() + "番ポートが開けませんでした。あきらめます。");
                            break;
                        }
                        mPort++;
                    }
                }
                catch
                {
                    if (mPort < mPortMax)
                    {
                        //MessageBox.Show(mPort.ToString()+"番ポートが開けませんでした。続行します。");
                    }
                    else
                    {
                        MessageBox.Show(mPort.ToString() + "番ポートが開けませんでした。あきらめます。");
                        break;
                    }
                    mPort++;
                }
            }
            Util.GetStringProperty("Base.InstanceId", ref name);
            //AskId(name);
        }

        private bool Connect(int port)
        {            
            if (usedPortList.Contains(port)) return false;
            if (server.ServerStart(port))
            {
                server.TcpMessageReceived += new TcpComServer.TcpMessageEventHandler(server_TcpMessageReceived);

                Application.ApplicationExit += new EventHandler(Application_ApplicationExit);

                string strHost = Dns.GetHostName();
                ip = this.GetIPAddress(strHost);

                usedPortList.Add(port);
                return true;
            }
            else
            {
                usedPortList.Add(port);
                return false;
            }
        }

        #region get IP
        /// <summary>
        /// 指定したホスト名またはURLのIPアドレスを取得する
        /// </summary>
        /// <param name="HostName">IPアドレスを取得するホスト名またはURL</param>
        /// <returns>IPアドレス(文字列)</returns>
        private string GetIPAddress(string HostName)
        {

            // 変数を宣言
            string strIP;
            IPHostEntry IPHstEnt;
            IPAddress IPAddrs;

            try
            {
                // コンピュータ名を指定してIPアドレスリストを取得
                IPHstEnt = System.Net.Dns.GetHostByName(HostName);

                //
                int adapterIndex = 0;
                string p = "";
                //if (Util.GetStringProperty("OscQRViewClientPlugin.AdapterIndex", ref p))
                if (Util.GetStringProperty("OSCCom.AdapterIndex", ref p))
                {
                    adapterIndex = int.Parse(p);
                }

                // IPリストの0番目を取得
                // 0番目はコンピュータのIPアドレス
                //IPAddrs = IPHstEnt.AddressList[0];//[1];//[0];
                IPAddrs = IPHstEnt.AddressList[adapterIndex];
                strIP = IPAddrs.ToString();
            }
            catch (System.Net.Sockets.SocketException SockEx)
            {
                // HostNameを解決出来ない場合の例外処理を記述
                strIP = "";
            }
            catch (System.Security.SecurityException SecuEx)
            {
                // アクセスするためのアクセス許可がなかった場合の例外処理を記述
                strIP = "";
            }

            return strIP;

        }
        #endregion

        private void Application_ApplicationExit(object sender, EventArgs e)
        {
            Disconnect();
        }

        private void Disconnect()
        {
            server.Dispose();
            server = null;
        }

        public void ConnectTransmitter(string serverIP, int serverPort)
        {
            this.serverIP = serverIP;
            this.serverPort = serverPort;
            if (!server.WriterConnected)
            {
                server.ConnectTransmitter(serverIP, serverPort);
            }
            //server.ConnectTransmitter(serverIP, serverPort);
        }

        #endregion

        public void Send(string senderName, string destName, string adr, string val)
        {
            Send(adr, val);
        }
        public void Send(string adr, string val)
        {
            if (!server.WriterConnected)
            {
                ConnectTransmitter(serverIP, serverPort);
            }
            if(server.WriterConnected)
                server.SendMessage(adr + " " + val);
        }

        //private void Receive()
        //{
        //    while (true)
        //    {
        //        try
        //        {
        //            OSCPacket msg = receiver.Receive();
        //            string adr = msg.Address;
        //            ArrayList objs = msg.Values;
        //            string data = "";
        //            bool first = true;
        //            foreach (object obj in objs)
        //            {
        //                if (first) first = false;
        //                else data += ", ";
        //                data += obj.ToString();
        //            }
        //            _Parse(adr, data);
        //        }
        //        catch
        //        {
        //        }
        //    }
        //}

        void server_TcpMessageReceived(object o, TcpComServer.TcpMessageEventArgs e)
        {

            //mutInvalidated.WaitOne();
            string []com = e.Message.Split(' ');
            _adr = com[0];  
            _data = com[1];
            if (MessageReceived != null) MessageReceived(this, new MessageEventArgs(DateTime.Now, "@any", "@any",_adr,_data));
            //received = true;
            //mutInvalidated.ReleaseMutex();
        }

        //private void timer_Tick(object sender, EventArgs e)
        //{
        //    mutInvalidated.WaitOne();
        //    if (received)
        //    {
        //        received = false;
        //        try
        //        {
        //            if (MessageReceived != null) MessageReceived(this, new MessageEventArgs("@any", "@any", _adr, _data));
        //        }
        //        catch { }
        //    }
        //    mutInvalidated.ReleaseMutex();
        //}

    }
}
